package com.treasure.mall.biz.base;

import com.treasure.mall.biz.vo.PageDataVO;
import com.treasure.mall.zbq.common.SqlDataReader;
import org.hibernate.query.internal.NativeQueryImpl;
import org.hibernate.transform.Transformers;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.PersistenceUnit;
import javax.persistence.Query;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 原生查询基类
 *
 * @author wm
 */
public abstract class BaseDaoService {


    @PersistenceUnit
    protected EntityManagerFactory emf;

    /**
     * 获取第一行第一列
     *
     * @param sql sql语句
     * @return object
     */
    protected Object getSingle(String sql) {
        EntityManager em = emf.createEntityManager();
        Query query = em.createNativeQuery(sql);
        List<Object[]> list = (List<Object[]>) query.getResultList();
        em.close();
        if (list.isEmpty()) {
            return null;
        }
        return list.get(0)[0];
    }

    /**
     * 执行sql
     *
     * @param sql sql语句
     * @return 受影响行数
     */
    protected int executeSql(String sql) {
        EntityManager em = emf.createEntityManager();
        Query nativeQuery = em.createNativeQuery(sql);
        em.close();
        return nativeQuery.executeUpdate();
    }

    /***
     * 执行udpate 或delete sql
     * @param sql
     * @return
     */
    protected int executeUpdate(String sql) {
        EntityManager em = emf.createEntityManager();
        Query nativeQuery = em.createNativeQuery(sql);
        em.getTransaction().begin();
        int i = nativeQuery.executeUpdate();
        em.getTransaction().commit();
        em.close();
        return i;
    }

    /**
     * 返回一条数据
     *
     * @param sql sql语句
     * @return 数据
     */
    protected SqlDataReader executeReader(String sql) {
        List<SqlDataReader> readerList = this.executeReaderList(sql);
        return readerList.size() > 0 ? readerList.get(0) : null;
    }

    /**
     * 返回数据列表
     *
     * @param sql sql语句
     * @return 列表
     */
    protected List<SqlDataReader> executeReaderList(String sql) {
        EntityManager em = emf.createEntityManager();
        Query query = em.createNativeQuery(sql);
//        query.unwrap(SQLQuery.class).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
        query.unwrap(NativeQueryImpl.class).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
        List list = query.getResultList();
        em.close();
        List<SqlDataReader> readerList = new ArrayList<>();
        for (Object obj : list) {
            readerList.add(this.convertMapToReader((Map<String, Object>) obj));
        }
        return readerList;
    }

    /**
     * 分页获取数据
     *
     * @param sql      sql语句，如“ order by create_time desc”
     * @param pageSize 每页数
     * @param page     页码
     * @return 分页数据
     */
    protected PageDataVO<SqlDataReader> executePageList(String sql, Integer pageSize, Integer page) {
        EntityManager em = emf.createEntityManager();
        Query query = em.createNativeQuery(sql);
        query.setFirstResult((page - 1) * pageSize);
        query.setMaxResults(pageSize);
        //query.unwrap(SQLQuery.class).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
        query.unwrap(NativeQueryImpl.class).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
        List<Map<String, Object>> list = (List<Map<String, Object>>) query.getResultList();
        em.close();
        List<SqlDataReader> readerList = new ArrayList<>();
        for (Map<String, Object> row : list) {
            readerList.add(new SqlDataReader(row));
        }
        //获取总数
        EntityManager em2 = emf.createEntityManager();
        Query countQuery = em2.createNativeQuery(this.buildCountSql(sql));
        long recordCount = ((BigInteger) countQuery.getSingleResult()).longValue();
        em2.close();
        PageDataVO<SqlDataReader> pageDataVO = new PageDataVO<>();
        pageDataVO.setPageIndex(page);
        pageDataVO.setPageSize(pageSize);
        pageDataVO.setTotal(recordCount);
        pageDataVO.setPageCount(pageDataVO.calculatePageCount());
        pageDataVO.setRows(readerList);
        return pageDataVO;
    }

    /**
     * 获取总数
     *
     * @param sql sql语句
     * @return
     */
    protected BigInteger getCount(String sql) {
        EntityManager em = emf.createEntityManager();
        Query countQuery = em.createNativeQuery(sql);
        BigInteger count = (BigInteger) countQuery.getSingleResult();
        em.close();
        return count;
    }

    /**
     * 将通用数据类型反射转化为对象
     *
     * @param readers   数据列表
     * @param beanClass 要转换的类
     * @param <T>       对象
     * @return 列表
     */
    protected <T> List<T> convertList(List<SqlDataReader> readers, Class<T> beanClass) {
        return readers.stream().map(reader -> reader.convert(beanClass)).collect(Collectors.toList());
    }

    /**
     * 将通用数据类型反射转化为对象列表
     *
     * @param readers  数据列表
     * @param function 函数(委托)
     * @return 列表
     */
    protected <T> List<T> convertList(List<SqlDataReader> readers, Function<SqlDataReader, T> function) {
        List<T> list = new ArrayList<>();
        if (readers != null) {
            for (SqlDataReader reader : readers) {
                list.add(function.apply(reader));
            }
        }
        return list;
    }

    /**
     * PageData转换类型
     *
     * @param originalData 原始pageData
     * @param function     函数(委托)
     * @param <E>          原类型
     * @param <T>          新类型
     * @return 新pageData
     */
    protected <E, T> PageDataVO<T> convertPageData(PageDataVO<E> originalData, Function<E, T> function) {
        PageDataVO<T> targetData = new PageDataVO<>();
        targetData.setPageCount(originalData.getPageCount());
        targetData.setPageIndex(originalData.getPageIndex());
        targetData.setPageSize(originalData.getPageSize());
        targetData.setTotal(originalData.getTotal());
        targetData.rows = new ArrayList<>();
        originalData.rows.forEach(row -> targetData.rows.add(function.apply(row)));
        return targetData;
    }

    protected String buildCountSql(String sql) {
        return "select count(*) FROM\n" +
                "(\n" +
                sql + "\n" +
                ") as tbcount";
    }

    private SqlDataReader convertMapToReader(Map<String, Object> map) {
        return new SqlDataReader(map);
    }
}